#pragma once

#include <future>
#include <functional>
#include <memory>

#include "../common/net.hpp"
#include "../common/message.hpp"
#include "../common/fields.hpp"
#include "../common/uuid.hpp"
#include "requestor.hpp"

namespace JsonMuduoRPC
{
    namespace client
    {
        // requestor中的处理是针对BaseMessage进行处理的
        // 用户在rpccaller中针对结果的处理是针对 RpcResponse里边的result进行的
        class RPCCaller
        {
        public:
            using ptr = std::shared_ptr<RPCCaller>;
            using JsonAsyncResponse = std::future<Json::Value>;
            using JsonResponseCallBack = std::function<void(const Json::Value &)>;

            RPCCaller(const Requestor::ptr &requestor) : _requestor(requestor) {}


            // 以同步的方式发送请求，等收到响应结果后返回
            bool call(const BaseConnection::ptr &con,
                      const std::string &method,
                      const Json::Value &params,
                      Json::Value &result)
            {
                // 1. 组织请求
                RPCRequest::ptr req = MessageFactory::create<RPCRequest>();
                req->setId(UUID::getUuidStr());
                req->setMethod(method);
                req->setMType(MType::REQ_RPC);
                req->setParams(params);

                // 2. 发送请求
                BaseMessage::ptr rsp;
                bool ret = _requestor->send(con, std::dynamic_pointer_cast<BaseMessage>(req), rsp);
                if (ret == false)
                {
                    LOG(ERROR, "method: %s, 同步RPC请求失败", method.c_str());
                    return false;
                }

                // 3. 等待响应
                LOG(DEBUG, "收到响应，进行解析，获取结果");
                RPCResponse::ptr rpc_rsp = std::dynamic_pointer_cast<RPCResponse>(rsp);
                if (rpc_rsp.get() == nullptr)
                {
                    LOG(ERROR, "RPC响应, 类型转换失败");
                    return false;
                }
                if (rpc_rsp->getRCode() != RCode::RCODE_OK)
                {
                    LOG(ERROR, "RPC同步请求出错: %s", errReason(rpc_rsp->getRCode()));
                    return false;
                }

                result = rpc_rsp->getResult();
                return true;
            }

            // 以异步的方式发送请求，发起调用后立即返回，在想获取结果的时候进行获取
            // 通过设置回调函数，在回调函数中设置promise的值（结果）
            bool call(const BaseConnection::ptr &con,
                      const std::string &method,
                      const Json::Value &params,
                      JsonAsyncResponse &result)
            {
                // 1. 组织请求
                RPCRequest::ptr req = MessageFactory::create<RPCRequest>();
                req->setId(UUID::getUuidStr());
                req->setMethod(method);
                req->setMType(MType::REQ_RPC);
                req->setParams(params);

                // 2. 发送请求
                std::shared_ptr<std::promise<Json::Value>> json_promise = std::make_shared<std::promise<Json::Value>>();
                result = json_promise->get_future();
                Requestor::RequestCallBack cb = std::bind(&RPCCaller::callBackAsync, this, json_promise, std::placeholders::_1);
                bool ret = _requestor->send(con, std::dynamic_pointer_cast<BaseMessage>(req), cb);
                if (ret == false)
                {
                    LOG(ERROR, "method: %s, 异步RPC请求失败", method.c_str());
                    return false;
                }

                return true;
            }

            bool call(const BaseConnection::ptr &con,
                      const std::string &method,
                      const Json::Value &params,
                      const JsonResponseCallBack &cb)
            {
                // 1. 组织请求
                RPCRequest::ptr req = MessageFactory::create<RPCRequest>();
                req->setId(UUID::getUuidStr());
                req->setMethod(method);
                req->setMType(MType::REQ_RPC);
                req->setParams(params);

                // 2. 发送请求
                Requestor::RequestCallBack req_cb = std::bind(&RPCCaller::callBack, this, cb, std::placeholders::_1);
                bool ret = _requestor->send(con, std::dynamic_pointer_cast<BaseMessage>(req), req_cb);
                if (ret == false)
                {
                    LOG(ERROR, "method: %s, 回调RPC请求失败", method.c_str());
                    return false;
                }

                return true;
            }

        private:
            void callBackAsync(std::shared_ptr<std::promise<Json::Value>> &result, const BaseMessage::ptr &rsp)
            {
                RPCResponse::ptr rpc_rsp = std::dynamic_pointer_cast<RPCResponse>(rsp);
                if (rpc_rsp.get() == nullptr)
                    LOG(ERROR, "RPC响应, 类型转换失败");
                if (rpc_rsp->getRCode() != RCode::RCODE_OK)
                    LOG(ERROR, "RPC异步请求出错: %s", errReason(rpc_rsp->getRCode()));
                else
                    result->set_value(rpc_rsp->getResult());
            }

            void callBack(const JsonResponseCallBack &cb, const BaseMessage::ptr &rsp)
            {
                RPCResponse::ptr rpc_rsp = std::dynamic_pointer_cast<RPCResponse>(rsp);
                if (rpc_rsp.get() == nullptr)
                    LOG(ERROR, "RPC响应, 类型转换失败");
                if (rpc_rsp->getRCode() != RCode::RCODE_OK)
                    LOG(ERROR, "RPC回调请求出错: %s", errReason(rpc_rsp->getRCode()));
                else
                    cb(rpc_rsp->getResult());
            }

        private:
            Requestor::ptr _requestor;
        };
    }
} // namespace JsonMuduoRPC
